///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.adapters {
	import flash.events.AsyncErrorEvent;
	import flash.events.EventDispatcher;
	import flash.events.SecurityErrorEvent;
	import flash.events.StatusEvent;
	import flash.net.LocalConnection;
	
	import sugarcookie.events.GenericEvent;
	
	import mx.logging.Log;
	import mx.logging.ILogger;
	
	 /**
	  * Dispatches events to and recieves events from loaded AS2 swfs that are utilizing the AS2 version of this class.
	  */
	public class ASBridge extends EventDispatcher {
		//--------------------------------------------------------------------------
	    //
	    //  Class constants
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * Defines the value of the <code>type</code> property of an <code>GenericEvent</code> event object.
		 * 
		 * <p>The properties of the event object have the following values:</p>
	     * <table class="innertable">
	     * <tr><th>Property</th><th>Value</th></tr>
	     * <tr><td><code>bubbles</code></td><td>true</td></tr>
	     * <tr><td><code>cancelable</code></td><td>false</td></tr>
	     * <tr><td><code>status</code></td><td>true</td></tr>
	     * <tr><td><code>isLoggable</code></td><td>true</td></tr>
	     * <tr><td><code>data</code></td><td>the object that was passed into the sendEvent in the AS2 version of this class.</td></tr>
	     * </table>
	     *
	     * @eventType adapterResultEvent
	     * @see sugarcookie.events.GenericEvent
		 */
		public static const ADAPTER_RESULT_EVENT:String = "adapterResultEvent";
		
		/**
		 * Defines the connection name of the LocalConnection object that originated from the AS2 version of this class.
		 * 
		 * @private
		 */
		private static const INCOMING_CONN_NAME:String = "AS2_AS3";
		
		/**
		 * Defines the connection name of the LocalConnection object that originites in this class.
		 * 
		 * @private
		 */
		private static const OUTGOING_CONN_NAME:String = "AS3_AS2";
		
		//--------------------------------------------------------------------------
	    //
	    //  Class properties
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * @private
		 */
		private static var _inst:ASBridge = null;
		
		/**
		 * @private
		 */
		private var _conn:LocalConnection;
		
		/**
		 * @private
		 */
		private var _log:ILogger;
		
		//--------------------------------------------------------------------------
	    //
	    //  Constructor
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * AS3 is unable to support private constructors, so a local class is used to keep this constructor from being called externally.
		 * 
		 * @param enforcer Local class, only accessable from within this package definition.
		 */
		public function ASBridge(enforcer:SingletonEnforcer) {
			_log = Log.getLogger("sugarcookie.adapters.ASBridge");
			
			_conn = new LocalConnection();
			_conn.client = this;
            _conn.addEventListener(StatusEvent.STATUS, onStatus);
            _conn.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
            _conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
            
            try {
                _conn.connect(ASBridge.INCOMING_CONN_NAME);
            } catch (error:ArgumentError) {
                _log.error("Unable to make connection on channel: "+ASBridge.INCOMING_CONN_NAME+", error thrown: "+error.toString());
            }
		}
		
		//--------------------------------------------------------------------------
	    //
	    //  Class methods
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * Class is intended to be used as a Singleton.
		 */
		public static function getInst():ASBridge {
			if (!_inst) _inst = new ASBridge(new SingletonEnforcer());
			return _inst;
		}
		
		/**
		 * Method to dispatch custom events with data into a loaded AS2 based SWF that is also untilizing the AS2 version of this class.
		 * 
		 * @param postEventType Defines the event type that is dispatched from the AS2 version of this class.
		 * @param data Object that can pass any data along with the event.
		 */
		public function sendEvent(postEventType:String=ASBridge.ADAPTER_RESULT_EVENT, data:Object=null):void {
			_log.debug("sendEvent - postEventType: "+postEventType);
			_conn.send(ASBridge.OUTGOING_CONN_NAME,"postEvent",postEventType,data);
		}
		
		// private members
		/**
		 * Recieves the local connection call from the AS2 version of this class.
		 * 
		 * @private
		 */
		private function postEvent(returnEvtType:String=ASBridge.ADAPTER_RESULT_EVENT,data:Object=null):void {
			_log.debug("postEvent - returnEvtType: "+returnEvtType);
			if (!dispatchEvent(new GenericEvent(returnEvtType,true,false,true,true,data))) {
				_log.error("Unable to dispatch result event of type: "+returnEvtType);
			}
		}
		
		/**
		 * Outputs the <code>onStatus</code> event to the logger.
		 * 
		 * @private
		 */
		private function onStatus(evt:StatusEvent):void {
			_log.debug("onStatus Event: "+evt.toString());
		}
		
		/**
		 * Outputs the <code>onAsyncError</code> event to the logger.
		 * 
		 * @private
		 */
		private function onAsyncError(evt:AsyncErrorEvent):void {
			_log.debug("onAsyncError Event: "+evt.toString());
		}
		
		/**
		 * 
		 * Outputs the <code>onSecurityError</code> event to the logger.
		 * 
		 * @private
		 */
		private function onSecurityError(evt:SecurityErrorEvent):void {
			_log.debug("onSecurityError Event: "+evt.toString());
		}
	}
}

class SingletonEnforcer {}